/*
 * #%L
 * Client
 * %%
 * Copyright (C) 2011 Ractoc.com
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package com.ractoc.opengamefinder.client.plugins;

import org.apache.log4j.Logger;

import com.ractoc.opengamefinder.api.messages.ChatEnterRoomMessage;
import com.ractoc.opengamefinder.api.messages.ChatLeaveRoomMessage;
import com.ractoc.opengamefinder.api.messages.ChatLineMessage;
import com.ractoc.opengamefinder.api.messages.GetAvatarMessage;
import com.ractoc.opengamefinder.api.results.MessageResultsErrorCodes;
import com.ractoc.opengamefinder.api.results.ChatEnterRoomMessageResult;
import com.ractoc.opengamefinder.api.results.ChatLeaveRoomMessageResult;
import com.ractoc.opengamefinder.api.results.ChatLineMessageResult;
import com.ractoc.opengamefinder.api.results.GetAvatarMessageResult;
import com.ractoc.opengamefinder.api.vo.AccountVO;
import com.ractoc.opengamefinder.client.plugins.messages.GuiMessage;
import com.ractoc.opengamefinder.client.plugins.nifty.ScreenType;
import com.ractoc.pffj.api.BasePluginMessageResult;
import com.ractoc.pffj.api.PluginLoaderException;
import com.ractoc.pffj.api.PluginMessage;
import com.ractoc.pffj.api.PluginMessageResultListener;
import com.ractoc.pffj.core.PluginController;
import com.ractoc.pffj.core.PluginException;

/**
 * Main chat plugin, handles all the chat messages.
 * @author ractoc
 * @version 0.1
 */
public class ChatPlugin extends BaseClientPlugin {

    private static final String ERROR_GUI_MESSAGE = "error processing the GUI message.";
    private static final String GUI_PLUGIN = "guiPlugin";
    private static Logger logger = Logger.getLogger(ChatPlugin.class.getName());
    private static AccountVO player;
    
    private static int lines;

    /**
     * Default constructor.
     */
    public ChatPlugin() {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final void load() throws PluginLoaderException {
        if (lines == 0) {
            logger.warn("Number of lines not set through the PFfJ configuration file, defaulting to 14 lines.");
            lines = 14;
        }
    }

    /**
     * {@inheritDoc}
     * Currently supports the following Messages:
     * <ul>
     * <li>ChatLineMessage</li>
     * <li>ChatLineMessageResult</li>
     ** <li>ChatEnterRoomMessage</li>
     * <li>ChatEnterRoomMessageResult</li>
     * <li>ChatLeaveRoomMessage</li>
     * </ul>
     */
    @Override
    public final void processMessage(final PluginMessage msg, final PluginMessageResultListener pmrListener) {
        BasePluginMessageResult result = null;
        logger.debug(msg.getClass().getName());
        if (msg instanceof ChatLineMessage) {
            final ChatLineMessage clMsg = (ChatLineMessage) msg;
            result = processChatLine(clMsg);
        } else if (msg instanceof ChatEnterRoomMessage) {
            final ChatEnterRoomMessage cerMsg = (ChatEnterRoomMessage) msg;
            result = processEnterRoom(cerMsg);
        } else if (msg instanceof ChatEnterRoomMessageResult) {
            final ChatEnterRoomMessageResult cerResult = (ChatEnterRoomMessageResult) msg;
            result = processEnterRoomResult(cerResult);
        } else if (msg instanceof ChatLeaveRoomMessage) {
            final ChatLeaveRoomMessage clrMsg = (ChatLeaveRoomMessage) msg;
            result = processLeaveRoom(clrMsg);
        }
        pmrListener.receivedResult(result);
    }
    
    public void setLines(int lines) {
        this.lines = lines;
    }

    public static int getLines() {
        return lines;
    }

    private BasePluginMessageResult processLeaveRoom(final ChatLeaveRoomMessage clrMsg) {
        final ChatLeaveRoomMessageResult clrResult = new ChatLeaveRoomMessageResult();
        clrResult.setErrorCode(MessageResultsErrorCodes.SUCCESS);
        logger.info("player " + clrMsg.getAccount().getName() + " is leaving room " + clrMsg.getRoomId());
        // here we send an leave room message to the server
        if (clrMsg.isOutbound()) {
            sendNetworkMessage(clrResult, clrMsg, this.getPluginId(), this.getPluginId(), false, true);
        } else {
            try {
                final GuiMessage guiMsg = new GuiMessage();
                guiMsg.setPayload(clrMsg);
                guiMsg.setType(ScreenType.CHAT);
                final BasePluginMessageResult guiResult = PluginController.getCurrentPluginController().processMessage(
                        GUI_PLUGIN, guiMsg);
                clrResult.setErrorCode(guiResult.getErrorCode());
            }
            catch (final PluginException e) {
                logger.error(ERROR_GUI_MESSAGE, e);
                clrResult.setErrorCode(MessageResultsErrorCodes.INTERNAL_ERROR);
            }
        }
        return clrResult;
    }

    private BasePluginMessageResult processEnterRoomResult(final ChatEnterRoomMessageResult cerResult) {
        BasePluginMessageResult result;
        if (cerResult.getErrorCode() == MessageResultsErrorCodes.SUCCESS) {
            for (AccountVO member : cerResult.getRoomMemberList()) {
                final ChatEnterRoomMessage cerMsg = new ChatEnterRoomMessage();
                cerMsg.setAccount(member);
                cerMsg.setRoomId(cerResult.getRoomId());
                cerMsg.setOutBound(false);
                processEnterRoom(cerMsg);
            }
        }
        result = cerResult;
        return result;
    }

    private BasePluginMessageResult processChatLine(final ChatLineMessage clMsg) {
        final ChatLineMessageResult clResult = new ChatLineMessageResult();
        clResult.setErrorCode(MessageResultsErrorCodes.SUCCESS);
        try {
            if (clMsg.isOutBound()) {
                clMsg.setAccount(player);
                logger.debug("account to send: " + clMsg.getAccount());
                sendNetworkMessage(clResult, clMsg, this.getPluginId(), this.getPluginId(), false, true);
            }

            final GetAvatarMessage gaMsg = new GetAvatarMessage();
            gaMsg.setAvatar(clMsg.getAccount().getAvatar());
            try {
                final GetAvatarMessageResult gaResult = (GetAvatarMessageResult) PluginController.getCurrentPluginController().processMessage(
                        "accountPlugin", gaMsg);
                if (gaResult.getErrorCode() != MessageResultsErrorCodes.SUCCESS) {
                    logger.warn("Unable to load the avatar image for user " + clMsg.getAccount().getId() + ", errorcode: " + gaResult.getErrorCode());
                } else {
                    logger.debug("setting avatar to " + gaResult.getAvatar());
                    if (gaResult.getAvatar().getFileName() != null) {
                        clMsg.getAccount().setAvatar(gaResult.getAvatar());
                    }
                }
            }
            catch (PluginException ex) {
                logger.warn("Unable to load the avatar image for user " + clMsg.getAccount().getId(), ex);
            }

            clMsg.setCurrentPlayer(clMsg.getAccount().equals(player));
            
            final GuiMessage guiMsg = new GuiMessage();
            guiMsg.setPayload(clMsg);
            guiMsg.setType(ScreenType.CHAT);
            final BasePluginMessageResult guiResult = PluginController.getCurrentPluginController().processMessage(
                    GUI_PLUGIN, guiMsg);
            clResult.setErrorCode(guiResult.getErrorCode());
        }
        catch (final PluginException e) {
            logger.error(ERROR_GUI_MESSAGE, e);
            clResult.setErrorCode(MessageResultsErrorCodes.INTERNAL_ERROR);
        }
        return clResult;
    }

    private BasePluginMessageResult processEnterRoom(final ChatEnterRoomMessage cerMsg) {
        final ChatEnterRoomMessageResult cerResult = new ChatEnterRoomMessageResult();
        // the first player to enter the room is the local player.
        if (player == null) {
            player = cerMsg.getAccount();
        }
        cerResult.setErrorCode(MessageResultsErrorCodes.SUCCESS);
        try {
            if (cerMsg.isOutBound()) {
                sendNetworkMessage(cerResult, cerMsg, this.getPluginId(), this.getPluginId(), false, true);
            } else {
                final GuiMessage guiMsg = new GuiMessage();
                cerMsg.setCurrentPlayer(player.equals(cerMsg.getAccount()));
                guiMsg.setPayload(cerMsg);
                guiMsg.setType(ScreenType.CHAT);
                final BasePluginMessageResult guiResult = PluginController.getCurrentPluginController().processMessage(
                        GUI_PLUGIN, guiMsg);
                cerResult.setErrorCode(guiResult.getErrorCode());
            }
        }
        catch (final PluginException e) {
            logger.error(ERROR_GUI_MESSAGE, e);
            cerResult.setErrorCode(MessageResultsErrorCodes.INTERNAL_ERROR);
        }
        return cerResult;
    }
}
